package com.hq.ims.data.quartz.utils;

import com.google.common.collect.Lists;
import com.hq.web.utils.ApplicationContextHelper;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

@Slf4j
@Component
public class QuartzUtils {

    private static String JOB_GROUP_NAME = "JOB_GROUP_DEFAULT";
    private static String TRIGGER_GROUP_NAME = "TRIGGER_GROUP_DEFAULT";

    public static Scheduler getDefaultScheduler() {
        SchedulerFactoryBean bean = ApplicationContextHelper.getBean(SchedulerFactoryBean.class);
        if (bean == null) {
            try {
                return StdSchedulerFactory.getDefaultScheduler();
            } catch (SchedulerException e) {
                throw new RuntimeException(e);
            }
        }
        return bean.getScheduler();
    }

    /**
     * 添加一个定时任务，使用默认的任务组名，触发器名，触发器组名
     *
     * @param scheduler 调度器
     * @param jobName   任务名
     * @param cls       任务处理类
     * @param params    任务参数
     * @param time      时间设置，参考quartz说明文档
     */
    public static void addJob(Scheduler scheduler, String jobName, Class<? extends Job> cls, Object params, String time) {
        try {
            //任务名，任务组，任务执行类
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("params", params);
            JobDetail jobDetail = newJob(cls).withIdentity(jobKey).setJobData(jobDataMap).build();
            //触发器
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            //触发器时间设定
            Trigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(time)).build();
            scheduler.scheduleJob(jobDetail, trigger);
            if (!scheduler.isShutdown()) {
                //启动
                scheduler.start();
                log.info("添加定时任务成功, 任务名jobName: {}", jobName);
            }
        } catch (Exception e) {
            throw new RuntimeException("添加定时任务失败: 任务名jobName：" + jobName + "，失败原因:" + e.getMessage());
        }
    }

    public static void addJob(String jobName, Class<? extends Job> cls, Object params, String time) {
        addJob(getDefaultScheduler(), jobName, cls, params, time);
    }

    /**
     * 添加一个定时任务
     *
     * @param scheduler        调度器
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param jobClass         任务
     * @param params           任务参数
     * @param time             时间设置，参考quartz说明文档
     */
    public static void addJob(Scheduler scheduler, String jobName, String jobGroupName, String triggerName,
                              String triggerGroupName, Class jobClass, Object params, String time) {
        try {
            JobKey jobKey = new JobKey(jobName, jobGroupName);
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put("params", params);
            JobDetail jobDetail = newJob(jobClass).withIdentity(jobKey).setJobData(jobDataMap).build();
            // 触发器
            TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
            Trigger trigger = newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule(time)).build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改一个任务的触发时间(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param scheduler 调度器
     * @param jobName
     * @param time
     */
    public static void modifyJobTime(Scheduler scheduler, String jobName, String time) {
        try {
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(time)) {
                JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                Class objJobClass = jobDetail.getJobClass();
                Object params = jobDetail.getJobDataMap().get("params");
                removeJob(scheduler, jobName);
                System.out.println("修改任务：" + jobName);
                addJob(scheduler, jobName, objJobClass, params, time);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改一个任务的触发时间
     *
     * @param scheduler        调度器
     * @param triggerName
     * @param triggerGroupName
     * @param time
     */
    public static void modifyJobTime(Scheduler scheduler, String triggerName, String triggerGroupName, String time) {
        try {
            TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }
            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(time)) {
                // 修改时间
                trigger.getTriggerBuilder().withSchedule(cronSchedule(time));
                // 重启触发器
                scheduler.resumeTrigger(triggerKey);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 移除一个任务(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param scheduler 调度器
     * @param jobName
     */
    public static void removeJob(Scheduler scheduler, String jobName) {
        try {
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            scheduler.deleteJob(jobKey);// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 移除一个任务(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param jobName
     */
    public static void removeJob(String jobName) {
        try {
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            scheduler.deleteJob(jobKey);// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 批量移除任务(使用默认的任务组名，触发器名，触发器组名)
     *
     * @param jobNameList
     */
    public static void removeJobs(List<String> jobNameList) {
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            List<JobKey> jobKeyList = Lists.newArrayList();
            for (String jobName : jobNameList) {
                TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
                scheduler.pauseTrigger(triggerKey);// 停止触发器
                scheduler.unscheduleJob(triggerKey);// 移除触发器
                JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
                jobKeyList.add(jobKey);
            }
            // 删除任务
            scheduler.deleteJobs(jobKeyList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 移除一个任务
     *
     * @param scheduler        调度器
     * @param jobName
     * @param jobGroupName
     * @param triggerName
     * @param triggerGroupName
     */
    public static void removeJob(Scheduler scheduler, String jobName, String jobGroupName, String triggerName,
                                 String triggerGroupName) {
        try {
            TriggerKey triggerKey = new TriggerKey(triggerName, triggerGroupName);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            JobKey jobKey = new JobKey(jobName, jobGroupName);
            scheduler.deleteJob(jobKey);// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 启动所有定时任务
     *
     * @param scheduler 调度器
     */
    public static void startJobs(Scheduler scheduler) {
        try {
            scheduler.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 关闭所有定时任务
     *
     * @param scheduler 调度器
     */
    public static void shutdownJobs(Scheduler scheduler) {
        try {
            if (!scheduler.isShutdown()) {
                scheduler.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将日期转换为cron表达式
     *
     * @param fireDate
     */
    public static String getCronStr(LocalDateTime fireDate) {
        //转换date
        Date date = Date.from(fireDate.atZone(ZoneId.systemDefault()).toInstant());
        String[] cronArr = new String[7];
        Arrays.fill(cronArr, "");
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.setTime(date);
        int second = calendar.get(java.util.Calendar.SECOND);
        int minute = calendar.get(java.util.Calendar.MINUTE);
        int hour = calendar.get(java.util.Calendar.HOUR_OF_DAY);
        int day = calendar.get(java.util.Calendar.DAY_OF_MONTH);
        int month = calendar.get(java.util.Calendar.MONTH) + 1;
        int year = calendar.get(Calendar.YEAR);

        cronArr[0] = second + "";
        cronArr[1] = minute + "";
        cronArr[2] = hour + "";

        cronArr[3] = day + "";
        cronArr[4] = month + "";
        cronArr[5] = "?";
        cronArr[6] = year + "";

        return String.join(" ", cronArr);
    }

}
